package com.stylefeng.guns.modular.assessment.calculate;

import com.stylefeng.guns.common.persistence.model.Assessment;
import com.stylefeng.guns.common.persistence.model.Indication;
import com.stylefeng.guns.core.util.DoubleUtil;
import com.stylefeng.guns.modular.indication.service.IIndicationService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

public abstract class SecondIndicationCalculator extends IndicationCalculator {

	@Autowired
	protected IIndicationService indicationService;

	public abstract List<ThirdIndicationCalculator> getThirdIndicationCalculatorList();

	@Override
	public Assessment get(Integer roadnetId, Date beginDate, Date endDate) {
		//Assessment assessment = getAssessmentDB(roadnetId, beginDate, endDate);
		//if (assessment != null) {
		//    assessment.setNexLvlList(getThirdIndicationResults(roadnetId, beginDate, endDate));
		//
		//} else {
		Assessment assessment = calculate(roadnetId, beginDate, endDate);
		//assessmentService.insert(assessment);
		//}

		setWarningLevel(assessment);

		return assessment;
	}

	private void setWarningLevel(Assessment assessment) {
		List<Assessment> thirdAssessments = assessment.getNexLvlList();
		//是否有三级指标超出正常区间
		boolean thirdIndicationHignRisk = thirdAssessments.stream().map(Assessment::getWarningLevel)
				.anyMatch(waringLevel -> waringLevel == Assessment.WARNING_LEVEL_HIGH);
		if (thirdIndicationHignRisk) {
			assessment.setWarningLevel(Assessment.WARNING_LEVEL_HIGH);
		} else {
			Indication indication = indicationService.selectById(getIndicationId());
			Double assessmentValue = assessment.getAssessmentValue();
			double max = indication.getMaxVal();
			double min = indication.getMinVal();
			if (assessmentValue >= max || assessmentValue < min) {
				assessment.setWarningLevel(Assessment.WARNING_LEVEL_HIGH);
			}
		}
	}

	private List<Assessment> getThirdIndicationResults(Integer roadnetId, Date beginDate, Date endDate) {
		return getThirdIndicationCalculatorList().stream()
				.map(thirdIndicationCalculator -> thirdIndicationCalculator.get(roadnetId, beginDate, endDate))
				.collect(Collectors.toList());
	}


	@Override
	public Assessment calculate(Integer roadnetId, Date beginDate, Date endDate) {
		List<Assessment> thirdIndicationResults = getThirdIndicationResults(roadnetId, beginDate, endDate);
		Assessment assessment = calculateSecondIndication(thirdIndicationResults, roadnetId, beginDate, endDate);
		assessment.setNexLvlList(thirdIndicationResults);
		return assessment;
	}


	private Assessment calculateSecondIndication(List<Assessment> thirdIndicationResults, Integer roadnetId,
			Date beginDate, Date endDate) {
		//是否直接跳到高风险
		Double resultVal = 0D;
		for (int j = 0; j < thirdIndicationResults.size(); j++) {
			Indication indication = indicationService.selectById(thirdIndicationResults.get(j).getIndicationId());

			Double max = indication.getMaxVal();
			Double min = indication.getMinVal();
			//三级指标的值
			Assessment thirdAssessment = thirdIndicationResults.get(j);
			Double thirdIndicationValue = thirdAssessment.getAssessmentValue();

			//权重
			Double weight = indication.getWeight();

			if (DoubleUtil.sub(thirdIndicationValue, min) < 0) {
				thirdIndicationValue = min;
			}

			double x;

			if (indication.getBigIsBetter() == 1) { //越大越优
				x = DoubleUtil.safeDiv(
						DoubleUtil.sub(max, thirdIndicationValue),
						DoubleUtil.sub(max, min)
				);
			}else { //越小越优
				x = DoubleUtil.safeDiv(
						DoubleUtil.sub(thirdIndicationValue, min),
						DoubleUtil.sub(max, min)
				);
			}

			Double k = 2d;
			Double ux = DoubleUtil.mul(2, Math.pow(x, k));
			resultVal += DoubleUtil.mul(DoubleUtil.add(x, ux), DoubleUtil.div(weight, 2));
		}

		Assessment result = genResult(resultVal, roadnetId, beginDate, endDate);
		return result;
	}


}
